package com.danger.Service;

import android.content.Context;
import android.content.Intent;
import android.os.Message;

import com.danger.Activity.MainActivity;
import com.danger.Db.ThreadDao;
import com.danger.Db.ThreadDaoImpl;
import com.danger.Model.FileInfo;
import com.danger.Model.ThreadInfo;

import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 下载任务类
 * Created by 俊 on 2016/6/8.
 */
public class DownloadTask {

    private Context context;
    private FileInfo fileInfo;
    private ThreadDao threadDao;
    private int finished = 0;
    public boolean isPause = false;
    //线程的数量
    private int threadCount = 1;
    //线程集合
    private List<DownloadThread> threadList;
    //线程池
    public static ExecutorService executorService = Executors.newCachedThreadPool();

    public DownloadTask(Context context, FileInfo fileInfo, int threadCount) {
        this.context = context;
        this.fileInfo = fileInfo;
        this.threadCount = threadCount;
        threadDao = new ThreadDaoImpl(context);
    }

    public void downLoad() {
        //读取数据库中的线程信息
        List<ThreadInfo> threadInfos = threadDao.getThreads(fileInfo.getUrl());
        if (threadInfos.size() == 0) {
            //获得每个线程下载的长度
            int length = fileInfo.getLength() / threadCount;
            for (int i = 0; i < threadCount; i++) {
                //创建线程信息
                ThreadInfo threadInfo = new ThreadInfo(i, fileInfo.getUrl(), length * i, (i + 1) * length - 1, 0);
                if (i == threadCount - 1) {
                    threadInfo.setEnd(fileInfo.getLength());
                }
                //添加到线程信息集合中
                threadInfos.add(threadInfo);
                //向数据库中插入一条信息
                threadDao.insertThread(threadInfo);
            }
        }
        threadList = new ArrayList<>();
        //启动多个线程进行下载
        for (ThreadInfo threadInfo : threadInfos) {
            DownloadThread thread = new DownloadThread(threadInfo);
//            thread.start();
            DownloadTask.executorService.execute(thread);
            //添加线程到集合中
            threadList.add(thread);
        }
    }

    /**
     * 下载线程
     */
    class DownloadThread extends Thread {

        private ThreadInfo threadInfo;
        //标识线程是否执行完毕
        public boolean isFinished = false;

        public DownloadThread(ThreadInfo threadInfo) {
            this.threadInfo = threadInfo;
        }

        @Override
        public void run() {
            super.run();
            HttpURLConnection conn = null;
            RandomAccessFile raf = null;
            InputStream inputStream = null;
            try {
                URL url = new URL(threadInfo.getUrl());
                conn = (HttpURLConnection) url.openConnection();
                conn.setConnectTimeout(3000);
                conn.setRequestMethod("GET");
                //设置下载位置
                int start = threadInfo.getStart() + threadInfo.getFinished();
                conn.setRequestProperty("Range", "bytes=" + start + "-" + threadInfo.getEnd());
                //设置文件写入位置
                File file = new File(DownloadService.DOWNLOAD_PATH, fileInfo.getFileName());
                raf = new RandomAccessFile(file, "rwd");
                raf.seek(start);

                Intent intent = new Intent(DownloadService.ACTION_UPDATE);

                //开始下载
                finished = threadInfo.getFinished() + finished;
                if (conn.getResponseCode() == HttpURLConnection.HTTP_PARTIAL) {
                    //读取数据
                    inputStream = conn.getInputStream();
                    byte[] buffer = new byte[1024 * 4];
                    int len = -1;
                    long time = System.currentTimeMillis();
                    while ((len = inputStream.read(buffer)) != -1) {
                        //写入文件
                        raf.write(buffer, 0, len);
                        //累加整个文件的完成进度
                        finished = finished + len;
                        //累加每个现成的额完成进度
                        threadInfo.setFinished(threadInfo.getFinished() + len);
                        if (System.currentTimeMillis() - time > 1000) {
                            time = System.currentTimeMillis();
                            intent.putExtra("finished", finished * 100 / fileInfo.getLength());
                            intent.putExtra("id", fileInfo.getId());
                            context.sendBroadcast(intent);
                        }
                        if (isPause) {
                            threadDao.updateThread(threadInfo.getUrl(), threadInfo.getId(), threadInfo.getFinished());
                            return;
                        }
                        //下载进度发送广播给Activity
//                        context.sendBroadcast(intent);
                        //下载暂停时保存下载进度
                    }
                    //标识线程执行完毕
                    isFinished = true;
                    //检查下载任务是否执行完毕
                    checkAllThreadFinished();
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    conn.disconnect();
                    inputStream.close();
                    raf.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 判断是否所有线程都执行完毕
     */
    private synchronized void checkAllThreadFinished() {
        boolean allFinished = true;
        //遍历线程集合，判断线程是否都执行完毕
        for (DownloadThread thread : threadList) {
            if (!thread.isFinished) {
                allFinished = false;
                break;
            }
        }
        if (allFinished) {
            //删除线程信息
            threadDao.deleteThread(fileInfo.getUrl());
            //发送广播通知UI下载任务结束
            Intent intent = new Intent(DownloadService.ACTION_FINISHED);
            intent.putExtra("fileInfo", fileInfo);
            context.sendBroadcast(intent);
        }
    }
}